package xyz.ibenben.zhongdian.system.service.impl;

import com.monitorjbl.xlsx.StreamingReader;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.entity.Example.Criteria;
import xyz.ibenben.zhongdian.common.annotation.SystemServiceLog;
import xyz.ibenben.zhongdian.common.constants.Constants;
import xyz.ibenben.zhongdian.common.exception.ExceptionEnum;
import xyz.ibenben.zhongdian.common.exception.MyException;
import xyz.ibenben.zhongdian.common.util.DateUtils;
import xyz.ibenben.zhongdian.common.util.ExcelUtils;
import xyz.ibenben.zhongdian.system.dao.ChinaCityDao;
import xyz.ibenben.zhongdian.system.dao.ChinaProvinceDao;
import xyz.ibenben.zhongdian.system.dao.ChinaRegionDao;
import xyz.ibenben.zhongdian.system.dao.HouseInfoDao;
import xyz.ibenben.zhongdian.system.entity.HouseImage;
import xyz.ibenben.zhongdian.system.entity.HouseInfo;
import xyz.ibenben.zhongdian.system.entity.ajax.AjaxJson;
import xyz.ibenben.zhongdian.system.form.HouseInfoForm;
import xyz.ibenben.zhongdian.system.mapper.HouseInfoMapper;
import xyz.ibenben.zhongdian.system.service.HouseImageService;
import xyz.ibenben.zhongdian.system.service.HouseInfoService;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;

/**
 * 房屋信息服务实现类
 * 提供了一些基本的服务，如根据主键查找房屋信息及图片、
 * 根据房屋名称查询记录、导出列表等方法。
 * 是此系统的主要服务类
 *
 * @author chenjian
 * @since 2017年9月27日上午10:57:28
 */
@Service
public class HouseInfoServiceImpl extends AbstractServiceImpl<HouseInfo> implements HouseInfoService {

    @Resource
    private HouseInfoDao houseInfoDao;
    @Resource
    private HouseInfoMapper houseInfoMapper;
    @Resource
    private HouseImageService houseImageService;
    @Resource
    private ChinaProvinceDao chinaProvinceDao;
    @Resource
    private ChinaCityDao chinaCityDao;
    @Resource
    private ChinaRegionDao chinaRegionDao;

    /**
     * findOneWithImage房屋信息
     *
     * @param id 房屋主键
     * @return 房屋信息
     */
    @Override
    @SystemServiceLog(description = "findOneWithImage房屋信息")
    public HouseInfo findOneWithImage(Long id) {
        HouseInfo info = houseInfoMapper.findWithLocation(id);
        List<HouseImage> list = houseImageService.findByHouseId(id);
        if (list != null && !list.isEmpty()) {
            //为房屋信息设置图像列表
            info.setList(list);
        }
        return info;
    }

    /**
     * findByHouseName房屋信息
     *
     * @param houseName 房屋名称
     * @return 房屋信息列表
     */
    @Override
    @SystemServiceLog(description = "findByHouseName房屋信息")
    public List<HouseInfo> findByHouseName(String houseName) {
        //通过房屋名称获取房屋信息列表
        Example example = new Example(HouseInfo.class);
        Criteria criteria = example.createCriteria();
        criteria.andEqualTo("house_name", houseName);
        return houseInfoDao.selectByExample(example);
    }

    /**
     * export房屋信息
     *
     * @param houseIds 房屋主键列表
     * @param request  请求
     * @param response 响应
     */
    @Override
    @SystemServiceLog(description = "export房屋信息")
    public void export(List<Long> houseIds, HttpServletRequest request, HttpServletResponse response) {
        List<HouseInfo> list;
        if (houseIds != null && !houseIds.isEmpty()) {
            //根据主键列表获取数据列表
            Example example = new Example(HouseInfo.class);
            Criteria criteria = example.createCriteria();
            criteria.andIn("id", houseIds);
            list = houseInfoDao.selectByExample(example);
        } else {
            //如果主键列表为空，获取所有数据
            list = houseInfoDao.selectAll();
        }
        response.setHeader("content-Type", "application/vnd.ms-excel");
        // 下载文件的默认名称
        try {
            response.setHeader("Content-Disposition", "attachment;filename=" +
                    URLEncoder.encode("HouseInfoList", "UTF-8") + ".xls");
        } catch (UnsupportedEncodingException e) {
            throw new MyException(ExceptionEnum.CODEEXCEPTION, e);
        }
        //编码
        response.setCharacterEncoding("UTF-8");
        HSSFWorkbook workbook = new HSSFWorkbook();
        //sheet名称
        HSSFSheet sheet = workbook.createSheet("统计表");
        //创建标题
        createTitle(workbook, sheet);
        //设置日期格式
        HSSFCellStyle style = workbook.createCellStyle();
        style.setDataFormat(HSSFDataFormat.getBuiltinFormat("yyyy/mm/dd"));
        //新增数据行，并且设置单元格数据
        int rowNum = 1;
        for (HouseInfo info : list) {
            //导出记录
            HSSFRow row = sheet.createRow(rowNum);
            row.createCell(0).setCellValue(info.getId());
            row.createCell(1).setCellValue(info.getHouseName());
            row.createCell(2).setCellValue(info.getRoomNumber());
            row.createCell(3).setCellValue(info.getDrawingNumber());
            row.createCell(4).setCellValue(info.getKitchenNumber());
            row.createCell(5).setCellValue(info.getRestroomNumber());
            row.createCell(6).setCellValue(info.getOrientation().getText());
            row.createCell(7).setCellValue(info.getHouseArea().doubleValue());
            row.createCell(8).setCellValue(info.getLayer());
            row.createCell(9).setCellValue(info.getTotalLayer());
            row.createCell(10).setCellValue(info.getPolt());
            row.createCell(11).setCellValue(info.getAddress());
            row.createCell(12).setCellValue(chinaProvinceDao.findByCode(info.getProvince()));
            row.createCell(13).setCellValue(chinaCityDao.findByCode(info.getCity()));
            row.createCell(14).setCellValue(chinaRegionDao.findByCode(info.getRegion()));
            row.createCell(15).setCellValue(info.getPurpose());
            row.createCell(16).setCellValue(DateUtils.getCurrentTime(info.getBuyTime(), "yyyy-MM-dd"));
            row.createCell(17).setCellValue(info.getPropertyRight());
            rowNum++;
        }
        try {
            //写到response里
            workbook.write(response.getOutputStream());
        } catch (IOException e) {
            throw new MyException(ExceptionEnum.OUTPUTEXCEPTION, e);
        }
    }

    /***
     * 创建表头
     * @param workbook 工作簿
     * @param sheet 工作表
     */
    private void createTitle(HSSFWorkbook workbook, HSSFSheet sheet) {
        HSSFRow row = sheet.createRow(0);
        //设置列宽，setColumnWidth的第二个参数要乘以256，这个参数的单位是1/256个字符宽度
        sheet.setColumnWidth(2, 12 * 256);
        sheet.setColumnWidth(3, 17 * 256);

        //设置为居中加粗
        HSSFCellStyle style = workbook.createCellStyle();
        HSSFFont font = workbook.createFont();
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        style.setFont(font);

        HSSFCell cell;
        //获取标题Map
        Map<String, String> map = Constants.getMap("houseInfo");
        Set<String> set = map.keySet();
        if (!set.isEmpty()) {
            int i = 0;
            for (String value : set) {
                //设置标题Title
                cell = row.createCell(i++);
                cell.setCellValue(value);
                cell.setCellStyle(style);
            }
        }
    }

    /**
     * importData房屋信息
     *
     * @param bytes   数据数组
     * @param request 请求
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    @SystemServiceLog(description = "importData房屋信息")
    public void importData(byte[] bytes, HttpServletRequest request) {
        //多线程进行导入，每次10行
        int rowNum = 10;
        int totalNum = 0;
        do {
            Workbook wk = StreamingReader.builder()
                    //缓存到内存中的行数，默认是10
                    .rowCacheSize(rowNum)
                    //读取资源时，缓存到内存的字节大小，默认是1024
                    .bufferSize(4096)
                    //打开资源，必须，可以是InputStream或者是File，注意：只能打开XLSX格式的文件
                    .open(new ByteArrayInputStream(bytes));
            Sheet sheet = wk.getSheetAt(0);
            if (totalNum == 0) {
                totalNum = sheet.getPhysicalNumberOfRows();
            }
            List<String> list = new ArrayList<>();
            //加入字段名称
            Map<String, String> map = Constants.getMap("houseInfo");
            for (Map.Entry<String, String> entry : map.entrySet()) {
                list.add(entry.getValue());
            }
            //处理数据得到Map
            List<Map<String, Object>> mapList = ExcelUtils.parseExcel(wk, list);
            try {
                //根据Map组装成实体列表
                List<HouseInfo> resultList = ExcelUtils.toObjectList(mapList, HouseInfo.class, "yyyy-MM-dd");
                //保存到数据库
                saveList(resultList, request);
            } catch (Exception e) {
                throw new MyException(ExceptionEnum.SYSTEMERROREXCEPTION, e);
            }
        } while (rowNum <= totalNum);
    }

    /**
     * 保存列表
     *
     * @param resultList 需要保存的列表
     * @param request    请求
     */
    private void saveList(List<HouseInfo> resultList, HttpServletRequest request) {
        if (resultList != null && !resultList.isEmpty()) {
            for (HouseInfo info : resultList) {
                //处理省份信息
                String provinceCode = chinaProvinceDao.findByName(info.getProvince());
                info.setProvince(provinceCode);
                //处理城市信息
                String cityCode = chinaCityDao.findByName(info.getCity(), provinceCode);
                info.setCity(cityCode);
                //处理区县信息
                String regionCode = chinaRegionDao.findByName(info.getRegion(), cityCode);
                info.setRegion(regionCode);
                this.save(info, request);
            }
        }
    }

    /**
     * findByCreateIdAndType房屋信息
     *
     * @param createId 创建人主键
     * @param type     类型
     * @return 房屋信息列表
     */
    @Override
    @SystemServiceLog(description = "findByCreateIdAndType房屋信息")
    public List<HouseInfo> findByCreateIdAndType(Long createId, int type) {
        Example example = new Example(HouseInfo.class);
        Criteria criteria = example.createCriteria();
        criteria.andEqualTo("createId", createId);
        criteria.andEqualTo("type", type);
        return houseInfoDao.selectByExample(example);
    }

    /**
     * countAll获取所有房屋信息列表
     *
     * @return 封装好的Json对象
     */
    @Override
    @SystemServiceLog(description = "countAll获取所有房屋信息列表")
    public AjaxJson getHouseInfoList() {
        AjaxJson aj = new AjaxJson();
        //Map结果集
        Map<String, Object> mapReturn = new HashMap<>();
        List<Map<String, Object>> list = houseInfoMapper.getHouseInfoList();
        if (list != null && !list.isEmpty()) {
            //为Echart放置数据，数据是否存在
            mapReturn.put("pieExsit", true);
            List<String> citys = new ArrayList<>();
            List<String> values = new ArrayList<>();
            for (Map<String, Object> map : list) {
                citys.add(map.get("city").toString());
                values.add(map.get("count").toString());
            }
            //X轴
            mapReturn.put("pieChatX", citys);
            //Y轴
            mapReturn.put("pieChatY", values);
            aj.setSuccess(true);
        } else {
            //数据不存在
            mapReturn.put("pieExsit", false);
            aj.setSuccess(false);
        }
        aj.setAttributes(mapReturn);
        return aj;
    }

    @Override
    public HouseInfo findWithLocation(Long id) {
        return houseInfoMapper.findWithLocation(id);
    }

    @Override
    public List<HouseInfo> findAll(HouseInfoForm houseInfoForm) {
        return houseInfoMapper.findAll(houseInfoForm);
    }

    @Override
    public Map<String, Object> getWholeChinaInfo() {
        Map<String, Object> mapReturn = new HashMap<>();
        List<Map<String, Object>> list = houseInfoMapper.getWholeChinaInfo();
        if (list != null && !list.isEmpty()) {
            //为Echart放置数据，数据是否存在
            mapReturn.put("mapExist", true);
            //数据
            mapReturn.put("mapData", list);
        } else {
            //数据不存在
            mapReturn.put("mapExist", false);
        }
        return mapReturn;
    }
}
